<?php
namespace app\common\model\feature\communal;
use app\Request;
use mall\utils\Tool;
use think\Exception;


/**
 * 文件上传处理
 * Class Upload
 * @package app\admin\model
 */
class File
{
    /**
     * 上传错误代码
     * @var array
     */
    const ERROR_CODE_LIST = [
        0   => '文件上传失败',
        1   => '上传文件过大',    //超出 php.ini 限制
        2   => '上传文件过大',    // 超出form 限制
        3   => '文件接收不完整',
        7   => '系统错误，上传失败',

        111 => '系统错误，请联系管理员',
        112 => '文件未被上传',

        211 => '文件类型配置缺失',
        212 => '缩略图类型不支持',
    ];


    const CONFIG_KEY = 'file';


    /**
     * 获取配置信息
     * @return array
     */
    private static function getConfig($type = null)
    {
        static $config;
        if(!$config) {
            $config = config(static::CONFIG_KEY);
        }
        if(is_null($type)) {
            return $config;
        }
        if(!is_array($config) || !array_key_exists('typeList',$config) || !is_array($config['typeList']) || !array_key_exists($type,$config['typeList'])) {
            static::throwError(211);
        }
        $typeDetails = $config['typeList'][$type];
        $typeDetails['domain'] = array_key_exists('diskToDomain',$config) && is_array($config['diskToDomain']) && array_key_exists($typeDetails['disk'],$config['diskToDomain'])?$config['diskToDomain'][$typeDetails['disk']]:\think\facade\Request::domain();
        return $typeDetails;
    }


    /**
     * 获取缩略图后缀
     */
    private static function getThumbSuffix($type) {
        if(empty($type)) {
            return null;
        }
        static $suffixList = null;
        if(is_null($suffixList)) {
            $config = config(static::CONFIG_KEY);
            $suffixList = array_key_exists('thumbTypeToSuffix',$config)?$config['thumbTypeToSuffix']:[];
        }
       if(!array_key_exists($type,$suffixList)) {
           static::throwError(212);
       }

       return '';   //暂时返回原图
       return $suffixList[$type];
    }

    /**
     * 上传文件
     * @param $type 文件类型
     * @param string $field form保存的字段
     * @param string $method    上传方式
     * @return url 返回文件名
     */
    public static function upload($type,$field = 'file',$method = 'form') {
        $config = static::getConfig($type);
        // 返回上传成功后的文件
        $filename = static::removeFile($config,$field);
        $url = static::url($filename,$type);
        // 返回文件名及图片地址
        return [
            'filename'  => $filename,
            'url'   => $url,
        ];
    }

    /**
     * 获取文件地址
     * @param $filesrc 文件src
     * @param string $type 类型
     * @param string $thumbType 缩略图类型
     * @return mixed|string 返回包含域名的地址
     */
    public static function url($filename,$type = null,$thumbType = null) {
        if(empty($filename)) {
            return $filename;
        } else if(!preg_match('/^http\:\/\//',$filename)) {
            $type = static::getType($filename,$type);
            $config = static::getConfig($type);
            $url = rtrim(array_key_exists('domain',$config)?$config['domain']:\think\facade\Request::domain(),'/');
            $url .= '/' . ltrim($filename,'/');
        }
        // 返回地址，并增加缩略图
        return $url . static::getThumbSuffix($thumbType);
    }




    /**
     * 判断文件是否存在
     * @param $filename
     * @param null $type
     * @return bool
     */
    public static function file_exists($filename,$type = null) {
        if(file_exists(static::getLocalSrc($filename,$type))) {
            return true;
        }
        return false;
        $url = static::url($filename,$type);
        $ch = curl_init();
        $timeout = 10;
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_HEADER, 1);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        $contents = curl_exec($ch);
        if(preg_match("/404/", $contents)){
            return false;
        }else{
            return true;
        }
    }

    /**
     * 获取本地存储
     * @param $filename
     * @param $type
     */
    private static function getLocalSrc($filename,$type) {
        $config = static::getConfig(static::getType($filename,$type));
        $config = config('filesystem.disks.' . $config['disk']);
        $filename = rtrim(rtrim($config['root'],'/'),'\\') . DIRECTORY_SEPARATOR . ltrim(ltrim($filename,'/'),'\\');
        return $filename;
    }


    /**
     * 获取文件类型
     * @param $filename
     * @param null $type
     * @return null
     */
    private static function getType($filename,$type = null) {
        if(is_null($type)) {
            $type = explode('/',$filename)[0];
        }
        return $type;
    }




    /**
     * 转移文件
     * @param $filePath
     * @return url 需要用于保存的url地址
     */
    private static function removeFile($config,$postField = 'file') {
        $validateList = [];
        $validateFields = [
            'fileSize'  => 'filesize',
            'fileExt'   => 'fileExt',
            'fileMime'  => 'fileMime',
            'image' => 'image'
        ];
        foreach($validateFields as $key=>$field) {
            if(array_key_exists($key,$config) && !empty($config[$key])){
                $validateList[] = $field . ':' . (is_array($config[$key])?implode(',',$config[$key]):$config[$key]);
            }
        }

        // 获取表单上传文件 例如上传了001.jpg
        $file = request()->file($postField);

        // 移动到框架应用根目录/public/uploads/ 目录下
        if($file){
            try{
                if(!empty($validateList)) {
                    validate([$postField => implode('|',$validateList)])->check(request()->file());
                }
                // 上传到本地服务器
                $savename = \think\facade\Filesystem::disk($config['disk'])->putFile($config['path'], $file,array_key_exists('rule',$config)?$config['rule']:null);
            } catch (\think\exception\ValidateException $e) {
                static::throwError($e->getMessage());
            }
        } else {
            static::throwError(112);
        }
        return $savename;
    }


    /**
     * 抛出异常
     * @param $code
     * @throws \Exception
     */
    private static function throwError($code)
    {
        $errorMsg = array_key_exists($code,static::ERROR_CODE_LIST)?static::ERROR_CODE_LIST[$code]:$code;
        throw new Exception($errorMsg);
    }

}
